/**
 * @class   wosh::ObjectAllocator
 * @brief   
 *
 *

 * Manager allocators:
 *  - Static allocator (built-in)
 *  - Dynamic allocator (as dll plugins)
 *
 *  - Remote allocators ( build a wrapper to a remote object, =location transparency)
 *
 * Rules:
 *  - Objects are destroyed by the allocator which instantiated it
 *
 * Allocation by:
 *  - classname
 *  - interface [version]
 *
 *
usa ireflection per forza

 *
 *
 *
 ****************************************************************************
 * @version 0.8.161 $Id: ObjectAllocator.h 2831 2010-08-02 22:15:14Z alex $
 * @author  Alessandro Polo
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ThreadS;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/

#ifndef __WOSH_Core_ObjectAllocator_H__
 #define __WOSH_Core_ObjectAllocator_H__

 #include <woshDefs.h>
 #include <core/Object.h>
 #include <core/LogContext.h>
 #include <core/Containers.h>
 #include <core/Serialization.h>

namespace wosh {

#undef WOSH_REGISTER
#define WOSH_REGISTER( CLASSNAME, PARENT_INTERFACE, VERSION, TMP ) \
	ObjectTypeAdapterT<CLASSNAME> my_register_##TMP(PARENT_INTERFACE, VERSION ); 

#undef WOSH_REGISTER_INTERFACE
#define WOSH_REGISTER_INTERFACE( CLASSNAME, PARENT_INTERFACE, VERSION, TMP ) \
	ObjectTypeAdapterAbstract my_register_##TMP(#CLASSNAME, PARENT_INTERFACE, VERSION ); 
 
/*
concepts: 

- EACH represented class has a ObjectTypeAdapter 'static' instance.
- ObjectTypeAdapter holds object's classname (+version), parent interface
- when a leaf is added nad its parent is missing, an 'emtpy' type for parent is created
- so a full tree may be built. having pure-or-declared abstract classes returning NULL on create

*/

/////////////////////////////////////////////////////////////////////////////////////////////////////////////

class ObjectTypeAdapter : public ObjectTypeInfo
 {
	public:
		ObjectTypeAdapter()
			: ObjectTypeInfo() { }

		ObjectTypeAdapter( const char* className, const char* parent_interface = "", double current_version = 0.0, bool abstract_class = false )
			: ObjectTypeInfo(className, parent_interface, current_version, abstract_class) { }

		ObjectTypeAdapter( const ObjectTypeAdapter& m )
			: ObjectTypeInfo(m) { }

		virtual ~ObjectTypeAdapter() { }

	public:
		virtual IReflection* create() = 0;
		virtual void destroy( IReflection* object ) = 0;

		virtual ObjectTypeAdapter* clone() const = 0;

	protected:
		void registerMySelf() const;

}; // class def

/////////////////////////////////////////////////////////////////////////////////////////////////////////////

template <typename ObjectType>
class ObjectTypeAdapterT : public ObjectTypeAdapter
 {
	WOSH_CLONE_CONSTRUCTOR(wosh::ObjectTypeAdapterT<ObjectType>)

	public:
		ObjectTypeAdapterT( const char* parent_interface = "", double current_version = 0.0 )
			: ObjectTypeAdapter(ObjectType::className(), parent_interface, current_version, false) {
			registerMySelf();
		}
		ObjectTypeAdapterT( const ObjectTypeAdapterT& m ) // DO NOT REGISTER ITSELF!!!
			: ObjectTypeAdapter(m) { }
		virtual ~ObjectTypeAdapterT() { }

	public:
		virtual ObjectType* create()					{ return new ObjectType(); }
		virtual void destroy( IReflection* object ) {
			if ( object == NULL ) return;
			delete object;
		 }

}; // class def

/////////////////////////////////////////////////////////////////////////////////////////////////////////////

class ObjectTypeAdapterAbstract : public ObjectTypeAdapter
{
	WOSH_CLONE_CONSTRUCTOR(wosh::ObjectTypeAdapterAbstract)

	public:
		ObjectTypeAdapterAbstract() // DO NOT REGISTER ITSELF!!!
			: ObjectTypeAdapter() { }
		ObjectTypeAdapterAbstract( const char* className, const char* parent_interface = "", double current_version = 0.0 )
			: ObjectTypeAdapter(className, parent_interface, current_version, true) { 
			registerMySelf();
		}
		ObjectTypeAdapterAbstract( const ObjectTypeAdapter& m ) // DO NOT REGISTER ITSELF!!!
			: ObjectTypeAdapter(m) { }
		ObjectTypeAdapterAbstract( const ObjectTypeAdapterAbstract& m ) // DO NOT REGISTER ITSELF!!!
			: ObjectTypeAdapter(m) { }
		virtual ~ObjectTypeAdapterAbstract() { }

	public:
		virtual IReflection* create()				{ return NULL; }
		virtual void destroy( IReflection* object ) {
			if ( object == NULL ) return;
			delete object;
		 }

}; // class def

/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////

class ObjectTypeNode
 {
	public:
		ObjectTypeNode() : info(NULL) { }
		ObjectTypeNode( ObjectTypeAdapter* obj ) : info(obj) { }
		~ObjectTypeNode() {
			if ( this->info != NULL )
				delete this->info;
		 }
	public:
		inline void setChild( const std::string& name ) {
			if ( isChild(name) ) return;
			this->children.push_back(name);
		 }
		void delChild( const std::string& name ) {
			std::vector<std::string>::iterator it;
			for( it=this->children.begin(); it!=this->children.end(); ++it ) {
				if ( *it != name ) continue;
				this->children.erase(it);
				return;
			 }
		 }
		bool isChild( const std::string& name ) const {
			std::vector<std::string>::const_iterator it;
			for( it=this->children.begin(); it!=this->children.end(); ++it ) {
				if ( *it == name ) return true;
			 }
			return false;
		 }
	public:
		ObjectTypeAdapter* info;
		std::vector<std::string> children;
};

class ObjectFactory;
class ObjectAllocator;
class Tree;
template <class T> class DataFieldCollector;
typedef ListT<ObjectAllocator*> tObjectAllocatorList;

class ObjectAllocator : public Object
 {
	WOSH_SERIALIZABLE(wosh::ObjectAllocator)

	typedef ListT<IReflection*> tIReflectionList;
	typedef MapT<std::string, ObjectTypeNode*> tStrObjectTypeNodeMap;


	public:
		/**
		 * @brief  Default constructor. Init log.
		 */
		ObjectAllocator();
		/**
		 * @brief  Destructor. Free types dataset.
		 */
		virtual ~ObjectAllocator();

	public:
		/**
		 * @brief  Check a class-type for existence. Reentrant.
		 * @param  className [in] full class name of the object (including namespace). It may be an abstract interface
		 * @param  version_pattern [in] version to be evaluated, 0.0 is *any* pattern
		 * @param  allocable_only [in] when true, it will filter abstract classes (only allocable class will be included)
		 * @return true if classtype exists and matchs the query; false else
		 */
		virtual bool isSupported( const std::string& className, double version_pattern = 0.0, bool allocable_only = false ) const;

		/**
		 * @brief  Create a on object of an argument class-type and up-cast it to selected class. Reentrant. Provided for convenience.
		 * @param  className [in] full class name of the object (including namespace). It may be an abstract interface,
		 *         in this case it will search for nearest/updated implementation of the interface
		 * @param  version_pattern [in] version to be evaluated, 0.0 is *any* pattern
		 * @return NULL if object can't be allocated; the new instance else, ownership is acquired by caller
		 * @see    createTypeOf()
		 * @note   dynamic cast will return NULL on casting errors; note that in there case, memory will be lost
		 */
		template <class DYNAMIC_CAST>
		DYNAMIC_CAST* createTypeOf( const std::string& className, double version_pattern = 0.0, bool strict = false ) {
			return dynamic_cast<DYNAMIC_CAST*>(createTypeOf(className, version_pattern, strict));
		 }

		/**
		 * @brief  Create an object of given type (class-name). Reentrant.
		 *         Object is registered in the allocators list, so it may be destroyed later within same scope.
		 * @param  className [in] full class name of the object (including namespace). It may be an abstract interface,
		 *         in this case it will search for nearest/updated implementation of the interface
		 * @param  version_pattern [in] version to be evaluated, 0.0 is *any* pattern
		 * @return NULL if object can't be allocated; the new instance else, ownership is acquired by caller
		 * @see    destroy()
		 */
		virtual IReflection* createTypeOf( const std::string& className, double version_pattern = 0.0, bool strict = false );

		/**
		 * @brief  Delete an object. Reentrant. This is a sort of 'delete object' but it is scoped within the original allocator.
		 *         It is convenient and save especially when using plugins and DLLs.
		 * @param  object [in] object to be destryoed (downcasted to IReflection interface)
		 * @return WRET_ERR_PARAM if argument is NULL or its owner-allocator was not found; WRET_OK else (on succeded deletion)
		 * @see    createTypeOf()
		 * @note   Object must have been allocated through createTypeOf() call (directly on indirecttly)
		 */
		virtual WRESULT destroy( IReflection* object );


	public:
		/**
		 * @brief  Register/update class-type. Reentrant.
		 * @param  info [in] struct holding information about the type, object is copied
		 * @return WRET_ERR_PARAM if classname is NULL or its name is empty; WRET_OK else
		 */
		WRESULT registerType( const ObjectTypeAdapter* info );

		/**
		 * @brief  Unregister class-type. Reentrant.
		 * @param  className [in] full class name of the object to be removed
		 * @param  remove_children [in] when true all inherited classes will be removed as well (default and usually false!)
		 * @return WRET_ERR_PARAM if classname is NULL or was not found; WRET_OK else
		 */
		WRESULT unRegisterType( const char* className, bool remove_children = false );


	public:
		WRESULT gatherInfoOf( std::vector<ObjectTypeInfo>& parent_list, const std::string& className, double version_pattern = 0.0 ) const;

		WRESULT findChildsOf( std::vector<ObjectTypeInfo>& class_list, const std::string& className, double version_pattern = 0.0, bool allocable = true ) const;


		WRESULT mergeTree_( Tree& obj_info_tree, bool children_tree = true ) const;
		void mergeTreeNodeChild_( const std::string& className, TreeNode* parentNode ) const;
		void mergeTreeNodeParent_( const std::string& className, TreeNode* parentNode ) const;

		static DataFieldCollector<ObjectAllocator>* getDataFields();

	protected:
		void dump();

	protected:
		void dumpChildrenOf( const std::string& className, FILE* outfile, int indent );
		void dumpParentOf( const std::string& className, FILE* outfile, int indent );
		int validateNode_( const ObjectTypeAdapter* currNode, double version_pattern, bool allocable_only ) const;
		ObjectTypeNode* findChildOf_( ObjectTypeNode* currentNode, double version_pattern, bool allocable_only );
		int addChildsOf_( std::vector<ObjectTypeInfo>& class_list, const ObjectTypeNode* node, bool allocable ) const;

	protected:
		const tIReflectionList& getAllocatedObjects() const		{ return this->allocatedObjects; }
		tIReflectionList& getAllocatedObjects()					{ return this->allocatedObjects; }

		const tStrObjectTypeNodeMap& getObjectsInfo() const		{ return this->typesInfo; }
		tStrObjectTypeNodeMap& getObjectsInfo()					{ return this->typesInfo; }

		// meyer singleton, created on first use, destroyed by compiler
		// items are NOT free on destructor
		static tObjectAllocatorList& getInstances() {
			static tObjectAllocatorList allocators_instances;
			return allocators_instances;
		 }

	protected:
		tStrObjectTypeNodeMap typesInfo;	///< information about types, tree model, stored as map
		tIReflectionList allocatedObjects;	///< references of objects allocated by myself, they cannot be really used for access, mostly here for debug
		mutable LogContext Log;				///< my own lo

		friend class wosh::ObjectFactory;


	private:
		ObjectAllocator( const ObjectAllocator& ) : Object() { }


}; // class def


}; // namespace wosh

#endif //__WOSH_Core_ObjectAllocator_H__
